package com.sinaapp.gavinzhang.GSpider.management;

import com.caucho.hessian.client.HessianProxyFactory;
import com.caucho.hessian.server.HessianServlet;
import com.sinaapp.gavinzhang.GSpider.common.IpUtil;
import com.sinaapp.gavinzhang.GSpider.common.ServletUtil;
import com.sinaapp.gavinzhang.GSpider.config.Constants;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * @author gavin
 * @version 1.0
 * @date 2016/3/19
 * @description 注册中心
 */
public class RegistrationCenter extends HessianServlet implements Register {
    private static final Logger logger = LoggerFactory.getLogger(RegistrationCenter.class);

    public final static String REGISTRATIONCENTER = "RegistrationCenter";
    public final static String URLDISPATCHER = "UrlDispatcher";
    public final static String PROCESSORDISPATCHER = "processorDispatcher";
    public final static String CONFIGDISPATCHER = "configDispatcher";

    public final static int DEFAULT_PORT = 20000;

    public static HessianProxyFactory checkFactory;

    private String host;
    private int port;
    private List<Stub> urlDispatcherList;
    private List<Stub> processorDispatcherList;
    private List<Stub> configDispatcherList;

    public RegistrationCenter() {
        this(DEFAULT_PORT);
    }

    public RegistrationCenter(int port) {
        this.port = port;
        urlDispatcherList = new ArrayList<>();
        processorDispatcherList = new ArrayList<>();
        configDispatcherList = new ArrayList<>();
        checkFactory = new HessianProxyFactory();
        logger.info("注册中心初始化成功");
    }

    /**
     * 在注册中心注册服务
     * 服务目前分为三类
     * 第一类：
     * 网址管理器，目前只需要一个网址管理器即可
     * 第二类：
     * 抓取集群管理器。可以注册多个
     * 第三类：
     * 配置状态管理器，用于提取抓取集群的配置bean，以及网址管理器的初始种子
     *
     * @param register 存根
     * @return Stub 如果注册失败返回空存根
     */
    @Override
    public Stub Registrate(Stub register) {
        if (register.getName().contains(URLDISPATCHER)) {
            for (Stub s : urlDispatcherList) {
                if (s.equals(register)) {
                    return Stub.getNoneStub();
                }
            }
            urlDispatcherList.add(register);
            logger.info("网址管理器注册成功: " + register.toString());
            return register;

        } else if (register.getName().contains(PROCESSORDISPATCHER)) {
            for (Stub s : processorDispatcherList) {
                if (s.equals(register))
                    return Stub.getNoneStub();
            }
            processorDispatcherList.add(register);
            logger.info("抓取集群管理器注册成功: " + register.toString());
            return register;

        } else if (register.getName().contains(CONFIGDISPATCHER)) {
            for (Stub s : configDispatcherList) {
                if (s.equals(register))
                    return Stub.getNoneStub();
            }
            configDispatcherList.add(register);
            logger.info("配置状态管理器注册成功: " + register.toString());
            return register;
        }
        return Stub.getNoneStub();
    }

    /**
     * 获取一个网址管理器，从注册中心的列表中找到一个使用次数最少的网址管理器存根。
     *
     * @return 网址管理器存根
     */
    @Override
    public Stub getURLDispatcher() {
        check(urlDispatcherList);
        Stub minStub = Stub.newStub();
        minStub.setUseCount(Long.MAX_VALUE);
        for (Stub s : urlDispatcherList) {
            if (s.getUseCount() < minStub.getUseCount()) {
                minStub = s;
            }
        }
        if (minStub.getUseCount() != Long.MAX_VALUE) {
            minStub.setUseCount(minStub.getUseCount() + 1);
            logger.info("得到网址管理器: " + minStub);
            return minStub;
        } else {
            return Stub.getNoneStub();
        }

    }

    /**
     * 获取抓取集群管理器，从注册中心的列表中找到一个使用次数最少的抓取集群管理器存根。
     *
     * @return 抓取集群管理器存根
     */
    @Override
    public Stub getProcessorDispatcher() {
        check(processorDispatcherList);
        Stub minStub = Stub.newStub();
        minStub.setUseCount(Long.MAX_VALUE);
        for (Stub s : processorDispatcherList) {
            if (s.getUseCount() < minStub.getUseCount()) {
                minStub = s;
            }
        }
        if (minStub.getUseCount() != Long.MAX_VALUE) {
            minStub.setUseCount(minStub.getUseCount() + 1);
            logger.info("得到抓取集群管理器: " + minStub);
            return minStub;
        } else {
            return Stub.getNoneStub();
        }
    }

    /**
     * 获取配置状态管理器，从注册中心的列表中找到一个使用次数最少的配置状态管理器存根。
     * 目前配置状态管理器应当只有一个
     *
     * @return 配置状态管理器存根
     */
    @Override
    public Stub getConfigDispatcher() {
        check(configDispatcherList);
        Stub minStub = Stub.newStub();
        minStub.setUseCount(Long.MAX_VALUE);
        for (Stub s : configDispatcherList) {
            if (s.getUseCount() < minStub.getUseCount()) {
                minStub = s;
            }
        }
        if (minStub.getUseCount() != Long.MAX_VALUE) {
            minStub.setUseCount(minStub.getUseCount() + 1);
            logger.info("得到配置管理器: " + minStub);
            return minStub;
        } else {
            return Stub.getNoneStub();
        }
    }

    /**
     * 获取所有抓取集群管理器
     *
     * @return 存根
     */
    @Override
    public List<Stub> getProcessorDispatchers() {
        check(processorDispatcherList);
        return processorDispatcherList;
    }

    /**
     * 获取所有网址管理器
     *
     * @return 存根
     */
    @Override
    public List<Stub> getURLDispatchers() {
        check(urlDispatcherList);
        return urlDispatcherList;
    }

    /**
     * 关闭所有存根对应的服务
     */
    @Override
    public void shutdownProcessor() {
        checkFactory.setConnectTimeout(Constants.STUBTIMEOUT);
        for (Stub s : new LinkedList<>(processorDispatcherList)) {
            try {
                HeartBeat dispatcher = (HeartBeat) checkFactory.create(HeartBeat.class, s.getName());
                dispatcher.shutdown();
            } catch (Exception e) {
                logger.warn("Stub has shutdown: " + s.getName());
                processorDispatcherList.remove(s);
            }
        }
    }

    /**
     * 检查存根列表中的存根所对应的服务器是否能提供服务，调用HeartBeat接口方法来判断。
     * 超时时间默认为 1000ms
     *
     * @param stubs
     */
    private void check(List<Stub> stubs) {
        checkFactory.setConnectTimeout(Constants.STUBTIMEOUT);
        for (Stub s : new LinkedList<>(stubs)) {
            try {
                HeartBeat dispatcher = (HeartBeat) checkFactory.create(HeartBeat.class, s.getName());
                dispatcher.echo();
            } catch (Exception e) {
                logger.warn("Stub can not connect: " + s.getName());
                stubs.remove(s);
                logger.info("Stub has removed: " + s.getName());
            }
        }
    }

    public static void setUp() throws Exception {
        logger.warn("注册中心端口号为:(默认)" + RegistrationCenter.DEFAULT_PORT);
        setUp(RegistrationCenter.DEFAULT_PORT);
    }

    public static void setUp(int port) throws Exception {
        logger.info("注册中心端口号为:" + port);
        Server server = new Server(port);
        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        server.setHandler(context);
        logger.info("GServer 启动中...");
        ServletUtil.addServlet(context, RegistrationCenter.class, "/" + RegistrationCenter.REGISTRATIONCENTER);
        logger.info("GServer 添加RPC注册中心服务成功!");
        server.start();
        logger.info("GServer 地址: " + server.getURI().toString());
        logger.info("GServer 启动成功!" + server.getState());
        //server.join();
    }

    public static void main(String[] args) throws Exception {
        RegistrationCenter.setUp();
        System.out.println(IpUtil.getRealIp());
        System.out.println("ok");
    }


}
